package com.yehui.alibaba.service.tcc.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.yehui.alibaba.dao.ProductDAO;
import com.yehui.alibaba.service.tcc.TCCProductService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * @author 业徽
 * @date 2021/8/5
 */
@Service("tCCProductService")
public class TCCProductServiceImpl implements TCCProductService {

    private static final Logger logger = LoggerFactory.getLogger(TCCProductServiceImpl.class);

    @Resource
    private ProductDAO productDao;

    /**
     * 扣减库存
     *
     * @param productId 商品 ID
     * @param amount    扣减数量
     * @throws Exception 扣减失败时抛出异常
     */
    @Override
    @DS(value = "product-ds")
    @Transactional(propagation = Propagation.REQUIRES_NEW) // 开启新事物
    public void reduceStock(BusinessActionContext actionContext, Long productId, Integer amount) throws Exception {
        logger.info("[reduceStock] 当前 XID: {}", RootContext.getXID());

        // 检查库存
        checkStock(productId, amount);

        logger.info("[reduceStock] 开始扣减 {} 库存", productId);
        // 扣减库存
        int updateCount = productDao.reduceStock(productId, amount);
        // 扣除成功
        if (updateCount == 0) {
            logger.warn("[reduceStock] 扣除 {} 库存失败", productId);
            throw new Exception("库存不足");
        }
        // 扣除失败
        logger.info("[reduceStock] 扣除 {} 库存成功", productId);
    }

    /**
     * Commit boolean.
     *
     * @param actionContext the action context
     * @return the boolean
     */
    @Override
    public boolean tccCommit(BusinessActionContext actionContext) {
        logger.info("tcc 提交. txId={}, context={}", RootContext.getXID(), actionContext);
        return true;
    }

    /**
     * Rollback boolean.
     *
     * @param actionContext the action context
     * @return the boolean
     */
    @Override
    public boolean tccRollback(BusinessActionContext actionContext) {
        logger.info("tcc 回滚. txId={}, context={}", RootContext.getXID(), actionContext);
        return true;
    }

    private void checkStock(Long productId, Integer requiredAmount) throws Exception {
        logger.info("[checkStock] 检查 {} 库存", productId);
        Integer stock = productDao.getStock(productId);
        if (stock < requiredAmount) {
            logger.warn("[checkStock] {} 库存不足，当前库存: {}", productId, stock);
            throw new Exception("库存不足");
        }
    }
}
